using System;
using MetaObjects.Contracts;

namespace MetaObjects.Core
{
	public class MetaField : IMetaField, IEntity<string>
	{
		object IEntity.Key { get { return Key; } }
		public string Key { get { return InternalName; } }
		public string InternalName { get; private set; }
		public string DisplayName { get; set; }
		public string Description { get; set; }
		public bool Required { get; set; }
		public bool ReadOnly { get; set; }
		public object DefaultValue { get; set; }
		public Action<object, object> SetField { get; set; }
		public Func<object, object> GetField { get; set; }

		public MetaField(string internalName)
		{
			InternalName = internalName;
		}
	}

	public abstract class MetaField<TEntity, TValue> : IMetaField<TEntity, TValue>
	{
		object IEntity.Key { get { return InternalName; } }
		public string InternalName { get; private set; }
		public string DisplayName { get; set; }
		public string Description { get; set; }
		public bool Required { get; set; }
		public bool ReadOnly { get; set; }
		object IMetaField.DefaultValue
		{
			get { return DefaultValue;  }
			set { DefaultValue = (TValue)value; }
		}
		public TValue DefaultValue { get; set; }

		Action<object, object> IMetaField.SetField { get { return (entity, value) => SetField((TEntity)entity, (TValue)value); } }
		Func<object, object> IMetaField.GetField { get { return entity => GetField((TEntity)entity); } }
		Action<object, TValue> IMetaField<TValue>.SetField { get { return (entity, value) => SetField((TEntity)entity, value); } }
		Func<object, TValue> IMetaField<TValue>.GetField { get { return entity => GetField((TEntity)entity); } }
		
		public abstract Action<TEntity, TValue> SetField { get; }
		public abstract Func<TEntity, TValue> GetField { get; }

		public MetaField(string internalName)
		{
			InternalName = internalName;
		}
	}
}